#pragma once
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <assert.h>

#define _BP_PLATFORM_WINDOW 0
#define _BP_PLATFORM_UNKNOW -1

#define _BP_STRING_CODE_UTF16 1
#define _BP_STRING_CODE_UTF8 2
#define _BP_STRING_CODE_ACP 3

#ifdef _MSC_VER
#define _BP_PLATFORM _BP_PLATFORM_WINDOW
#include <Windows.h>

#ifdef _DEBUG
#define _BP_DEBUG 1

#else
#define _BP_DEBUG 0

#endif

#else
#define _BP_PLATFORM _BP_PLATFORM_UNKNOW

#endif

#if _BP_DEBUG == 1
#define _BP_ASSERT(cond) assert(cond)

#else
#define _BP_ASSERT(cond) ((void)(cond))

#endif

#define _BP_EXPORT
#define _BP_API __stdcall
#define _BP_INLINE __inline

typedef uint8_t bp_bool;
#define BP_TRUE ((bp_bool)1)
#define BP_FALSE ((bp_bool)0)
#define _BP_BOOL_CAST(cond) ((cond) ? BP_TRUE : BP_FALSE)

typedef uint8_t bp_byte_t;
typedef uint16_t bp_uint16_t;
typedef uint32_t bp_uint32_t;

typedef bp_byte_t bp_mbchar_t;
typedef bp_mbchar_t bp_char8_t;
typedef bp_uint16_t bp_char16_t;
typedef bp_uint32_t bp_char32_t;

typedef enum _bp_string_encode {
	bp_string_encode_utf8 = 0,
	bp_string_encode_utf16le,
	bp_string_encode_utf16be,
	bp_string_encode_ansi
}bp_string_encode;

typedef enum _bp_byte_order {
	bp_little_endian = 0,
	bp_big_endian = 1
}bp_byte_order;

#define _BP_SAFE_SET_PTR(ptr, v) if (ptr) *(ptr) = (v)

#define _BP_MAKE_BYTE_MASK(b, mask) ((bp_byte_t)((b) & (mask)))
#define _BP_MAKE_BYTE(b) _BP_MAKE_BYTE_MASK(b, 0xFF)

#define _BP_LITTLE_ENDIAN_WORD_LBYTE(word) _BP_MAKE_BYTE(word) 
#define _BP_LITTLE_ENDIAN_WORD_HBYTE(word) _BP_MAKE_BYTE((word) >> 8)
#define _BP_LITTLE_ENDIAN_DWORD_LWORD(dword) ((uint16_t)((dword) & 0xFFFF))
#define _BP_LITTLE_ENDIAN_DWORD_HWORD(dword) ((uint16_t)(((dword) >> 16) & 0xFFFF))
#define _BP_LITTLE_ENDIAN_DWORD_BYTE_I(dword, idx) _BP_MAKE_BYTE(((bp_byte_t *)&(dword))[(idx) & 0x3])
#define _BP_LITTLE_ENDIAN_DWORD_BYTE0(dword) _BP_LITTLE_ENDIAN_DWORD_BYTE_I(dword, 0)
#define _BP_LITTLE_ENDIAN_DWORD_BYTE1(dword) _BP_LITTLE_ENDIAN_DWORD_BYTE_I(dword, 1)
#define _BP_LITTLE_ENDIAN_DWORD_BYTE2(dword) _BP_LITTLE_ENDIAN_DWORD_BYTE_I(dword, 2)
#define _BP_LITTLE_ENDIAN_DWORD_BYTE3(dword) _BP_LITTLE_ENDIAN_DWORD_BYTE_I(dword, 3)

#define _BP_BIG_ENDIAN_WORD_LBYTE(word) _BP_LITTLE_ENDIAN_WORD_HBYTE(word)
#define _BP_BIG_ENDIAN_WORD_HBYTE(word) _BP_LITTLE_ENDIAN_WORD_LBYTE(word)
#define _BP_BIG_ENDIAN_DWORD_LWORD(dword) _BP_LITTLE_ENDIAN_DWORD_HWORD(dword)
#define _BP_BIG_ENDIAN_DWORD_HWORD(dword) _BP_LITTLE_ENDIAN_DWORD_LWORD(dword)
#define _BP_BIG_ENDIAN_DWORD_BYTE_I(dword, idx) _BP_LITTLE_ENDIAN_DWORD_BYTE_I(dword, 3 - idx)
#define _BP_BIG_ENDIAN_DWORD_BYTE0(dword) _BP_LITTLE_ENDIAN_DWORD_BYTE3(dword)
#define _BP_BIG_ENDIAN_DWORD_BYTE1(dword) _BP_LITTLE_ENDIAN_DWORD_BYTE2(dword)
#define _BP_BIG_ENDIAN_DWORD_BYTE2(dword) _BP_LITTLE_ENDIAN_DWORD_BYTE1(dword)
#define _BP_BIG_ENDIAN_DWORD_BYTE3(dword) _BP_LITTLE_ENDIAN_DWORD_BYTE0(dword)

#define _BP_MAKE_LETTLE_ENDIAN_WORD(b0, b1) \
	((((bp_uint16_t)(b0)) & 0xFF) \
	| ((((bp_uint16_t)(b1)) << 8) & 0xFF00))
#define _BP_MAKE_BIG_ENDIAN_WORD(b0, b1) _BP_MAKE_LETTLE_ENDIAN_WORD(b1, b0)

#define _BP_WORD_BE_TO_LE(be) _BP_MAKE_LETTLE_ENDIAN_WORD(_BP_BIG_ENDIAN_WORD_LBYTE(be), _BP_BIG_ENDIAN_WORD_HBYTE(be))
#define _BP_WORD_LE_TO_BE(le) _BP_MAKE_BIG_ENDIAN_WORD(_BP_LITTLE_ENDIAN_WORD_LBYTE(le), _BP_LITTLE_ENDIAN_WORD_HBYTE(le))

#define _BP_MAKE_LITTLE_ENDIAN_DWORD(b0, b1, b2, b3) \
	((((bp_uint32_t)(b0)) & 0xFF) \
	| ((((bp_uint32_t)(b1)) << 8) & 0xFF00) \
	| ((((bp_uint32_t)(b2)) << 16) & 0xFF0000) \
	| ((((bp_uint32_t)(b3)) << 24) & 0xFF000000))
#define _BP_MAKE_BIG_ENDIAN_DWORD(b0, b1, b2, b3) _BP_MAKE_LITTLE_ENDIAN_DWORD(b3, b2, b1, b0)

#define _BP_DWORD_BE_TO_LE(be) \
	_BP_MAKE_LITTLE_ENDIAN_DWORD(_BP_BIG_ENDIAN_DWORD_BYTE0(be), _BP_BIG_ENDIAN_DWORD_BYTE1(be), _BP_BIG_ENDIAN_DWORD_BYTE2(be), _BP_BIG_ENDIAN_DWORD_BYTE3(be))
#define _BP_DWORD_LE_TO_BE(le) \
	_BP_MAKE_BIG_ENDIAN_DWORD(_BP_LITTLE_ENDIAN_DWORD_BYTE0(le), _BP_LITTLE_ENDIAN_DWORD_BYTE1(le), _BP_LITTLE_ENDIAN_DWORD_BYTE2(le), _BP_LITTLE_ENDIAN_DWORD_BYTE3(le))